package controller

import (
	"context"

	"github.com/adwindone/sdk-go/log"
	"github.com/adwindone/sdk-go/model/blockchain"
	"github.com/adwindone/sdk-go/model/common"
	"github.com/adwindone/sdk-go/model/controller"
	"github.com/adwindone/sdk-go/model/request"
	"github.com/adwindone/sdk-go/model/response"

	"go.uber.org/zap"
	grpc "google.golang.org/grpc"
)

// PeopleChainController provides interfaces for blockchain information retrieval, transaction sending, and node management.
type PeopleChainController interface {
	// GetBlockNumber returns the current block height. If flag is true, returns the Pending block height; if false, returns the latest block height.
	GetBlockNumber(ctx context.Context, flag bool) (uint64, error)
	// GetBlockHash returns the block hash at the specified block height.
	GetBlockHash(ctx context.Context, blockNumber uint64) (string, error)
	// GetNodeStatus returns the current node status.
	GetNodeStatus(ctx context.Context) (*response.NodeStatus, error)
	// SendRawTransaction sends a transaction to the blockchain.
	SendRawTransaction(ctx context.Context, rtx *request.Transaction) (string, error)
	// SendRawTransactions sends multiple transactions to the blockchain.
	SendRawTransactions(ctx context.Context, rtxs []*request.Transaction) ([]string, error)
	// GetTransaction returns transaction information by transaction hash.
	GetTransaction(ctx context.Context, txHash string) (*response.RawTransaction, error)
	// GetTransactionBlockNumber returns the block height by transaction hash.
	GetTransactionBlockNumber(ctx context.Context, blockHash string) (uint64, error)
	// GetTransactionIndex returns the transaction index in block by transaction hash.
	GetTransactionIndex(ctx context.Context, txHash string) (uint64, error)
	// GetBlockByHash returns block information by block hash.
	GetBlockByHash(ctx context.Context, blockHash string) (*blockchain.CompactBlock, error)
	// GetHeightByHash returns block height by block hash.
	GetHeightByHash(ctx context.Context, blockHash string) (uint64, error)
	// GetBlockByNumber returns block information by block height.
	GetBlockByNumber(ctx context.Context, blockNumber uint64) (*blockchain.CompactBlock, error)
	// GetBlockDetailByNumber returns block detail information (including transaction information) by block height.
	GetBlockDetailByNumber(ctx context.Context, blockNumber uint64) (*blockchain.Block, error)
	// GetStateRootByNumber returns the StateRoot (root hash value of state tree) by block height.
	GetStateRootByNumber(ctx context.Context, blockNumber uint64) (*common.StateRoot, error)
	// GetProofByNumber returns the Proof (block legal proof) by block height.
	GetProofByNumber(ctx context.Context, blockNumber uint64) (*common.Proof, error)
	// GetSystemConfig returns the current system configuration.
	GetSystemConfig(ctx context.Context) (*controller.SystemConfig, error)
	// GetSystemConfigByNumber returns the system configuration by block height.
	GetSystemConfigByNumber(ctx context.Context, blockNumber uint64) (*controller.SystemConfig, error)
	// AddNode adds a node to the blockchain network.
	AddNode(ctx context.Context, in *common.NodeNetInfo) (*common.StatusCode, error)
	// GetCrossChainProof returns the cross-chain proof by transaction hash.
	GetCrossChainProof(ctx context.Context, txHash string) (*controller.CrossChainProof, error)
}

type peopleChainControllerManage struct {
	controllerService controller.RPCServiceClient
	log               *zap.Logger
}

var _ PeopleChainController = (*peopleChainControllerManage)(nil)

// NewPeopleChainControllerManage creates a new PeopleChainController instance.
func NewPeopleChainControllerManage(cc *grpc.ClientConn) *peopleChainControllerManage {
	return &peopleChainControllerManage{
		controllerService: controller.NewRPCServiceClient(cc),
		log:               log.NewLogger(log.SetAppName("controller")),
	}
}
